package com.base.conn;


import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import com.receive.game.message.ReceivedGameMessage;


public class ServerConnBase {
	
	private final int serverPort;
	private final String serverIpString;
	private final Bootstrap bootstrap;
	private Channel channel;
	//安全消息队列 缓存消息
	private final ConcurrentLinkedQueue<String> sendMessageQueue ;
	private static ConcurrentLinkedQueue<BaseServiceSession> reciveMessageQueue;
	
	public ServerConnBase(String ip,int port) {
		
		serverPort = port;
		serverIpString = ip;
		sendMessageQueue = new ConcurrentLinkedQueue<>();
		reciveMessageQueue = new ConcurrentLinkedQueue<>();
		bootstrap = new Bootstrap();
	}
	
	public void run() {
		EventLoopGroup workerLoopGroup = new NioEventLoopGroup();
		try {
			bootstrap.group(workerLoopGroup);
			bootstrap.channel(NioSocketChannel.class);
			bootstrap.remoteAddress(serverIpString,serverPort);
			bootstrap.option(ChannelOption.ALLOCATOR,PooledByteBufAllocator.DEFAULT);
			bootstrap.handler(new ChannelInitializer<SocketChannel>() {
				protected void initChannel(SocketChannel ch) {
                	ChannelPipeline pipeline = ch.pipeline();
                    ByteBuf byteBuf = Unpooled.copiedBuffer("$_".getBytes());
                    pipeline.addLast(new DelimiterBasedFrameDecoder(1024,byteBuf));
                    pipeline.addLast(new StringDecoder());
                    pipeline.addLast(new StringEncoder());
                    pipeline.addLast(ServerConnBaseHandler.INSTANCE_CONN_HANDLER);
				}
			});
			ChannelFuture future = bootstrap.connect();
			future.addListener((ChannelFuture futureListener)->
			{
				if(futureListener.isSuccess()) {
					System.out.println("客户端链接成功");
				}else {
					System.out.println("客户端链接失败");
				}
				
			});
			future.sync();
			channel = future.channel();
			ExecutorService singleThreadExecutorServiceSend = Executors.newSingleThreadExecutor();
			singleThreadExecutorServiceSend.execute(() -> {
				while(true){
					if(!sendMessageQueue.isEmpty()) {
						String strMessageString = sendMessageQueue.poll();
						byte[] bytes;
						bytes = strMessageString.getBytes(StandardCharsets.UTF_8);
						ByteBuf bufferBuf = channel.alloc().buffer();
						bufferBuf.writeBytes(bytes);
						channel.writeAndFlush(bufferBuf);
					}else {
						 try {
							Thread.sleep(500);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			});
			
			ExecutorService singleThreadExecutorServiceRevice = Executors.newSingleThreadExecutor();
			singleThreadExecutorServiceRevice.execute(() -> {
				while(true){
					if(!reciveMessageQueue.isEmpty()) {
						BaseServiceSession baseServiceSession = reciveMessageQueue.poll();
						ReceivedGameMessage.Read(baseServiceSession);
					}else {
						 try {
							Thread.sleep(500);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			});
		} catch (Exception e) {
			e.printStackTrace();
			workerLoopGroup.shutdownGracefully();
		}
	}

	public void SendMessage(String msg) {
		//只是负责向消息队列中丢消息
		sendMessageQueue.offer(msg);
	}
	
	public static void ReciveMessage(ChannelHandlerContext ctx, Object msg) {
		BaseServiceSession baseServiceSession = new BaseServiceSession(ctx, msg.toString());
		reciveMessageQueue.offer(baseServiceSession);
	}

}
